package cc.linker.steplink.crm.service.impl;

import cc.linker.steplink.crm.commons.BeanMapUtils;
import cc.linker.steplink.crm.commons.Constants;
import cc.linker.steplink.crm.commons.http.HttpService;
import cc.linker.steplink.crm.commons.model.PcUserInfo;
import cc.linker.steplink.crm.commons.utils.CalendarUtils;
import cc.linker.steplink.crm.commons.utils.CityFormatReplaceUtils;
import cc.linker.steplink.crm.commons.utils.UUIDUtils;
import cc.linker.steplink.crm.dao.PreciseDao;
import cc.linker.steplink.crm.dao.SelfDao;
import cc.linker.steplink.crm.domain.AuthorTask;
import cc.linker.steplink.crm.domain.Precise;
import cc.linker.steplink.crm.merchant.dao.NewMallDao;
import cc.linker.steplink.crm.merchant.pojo.PersonGroupDTO;
import cc.linker.steplink.crm.merchant.service.PersonnelService;
import cc.linker.steplink.crm.merchanth5.commons.UserInfoUtil;
import cc.linker.steplink.crm.response.GlobalException;
import cc.linker.steplink.crm.response.ResponseCode;
import cc.linker.steplink.crm.response.ResponseException;
import cc.linker.steplink.crm.service.CustomerService;
import cc.linker.steplink.crm.service.IPreciseService;
import cc.linker.steplink.crm.service.ISysConfig;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.util.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PreciseServiceImpl implements IPreciseService {

    @Autowired
    private PreciseDao preciseDao;

    @Autowired
    private SelfDao selfDao;

    @Value("${system.scrm.wxMatrix}")
    private String wxurl;
    @Autowired
    private HttpService httpService;
    @Autowired
    private NewMallDao newMallDao;
    @Autowired
    private CustomerService customerService;

    @Autowired
    private UserInfoUtil userInfoUtil;

    @Autowired
    private PersonnelService personnelService;

    @Autowired
    private ISysConfig sysConfig;


    @Override
    public List<Map<String, Object>> listPrecise(Map<String, Object> map) throws Exception {
        List<Map<String, Object>> res = preciseDao.listPrecise(map);
        for (Map<String, Object> x : res) {
            String type = (String) x.get("type");
            String groupName = null;
            // 如果是【千人邮件推送】，在author_group中查询分组信息
            if ("email".equals(x.get("type"))) {
                groupName = preciseDao.getPreciseDemoGroupNameByIds(x.get("groupId").toString());
            }
            // 如果是其他，在t_crm_tbl_group中查询分组信息
            else {
                groupName = preciseDao.getGroupNameByIds(x.get("groupId").toString());
                // 如果是微信统计，进行数据加和
                if ("wx".equals(x.get("type"))) {
                    if (Integer.parseInt(x.get("touchNum").toString()) == 0 || StringUtils.isEmpty(x.get("touchNum"))) {
                        Integer touchNum = getTouchNum(x.get("taskId").toString());
                        x.put("touchNum", touchNum);
                    }
                }
            }
            x.put("groupName", groupName);
        }
        return res;
    }

    @Override
    public void addPrecise(Precise precise) {
        if (StringUtils.isEmpty(precise.getTaskName())) {
            throw new GlobalException(new ResponseException(400, "计划名称不能为空"));
        }
        if (StringUtils.isEmpty(precise.getGroupId())) {
            throw new GlobalException(new ResponseException(400, "人群不能为空"));
        }
        if (StringUtils.isEmpty(precise.getSendTime())) {
            throw new GlobalException(new ResponseException(400, "推送时间不能为空"));
        }
        if (StringUtils.isEmpty(precise.getContent())) {
            throw new GlobalException(new ResponseException(400, "推送内容不能为空"));
        }
        if (StringUtils.isEmpty(precise.getCreateUserId())) {
            throw new GlobalException(ResponseCode.INFO_OBTAIN_FAIL);
        }
        if (precise.getTaskId().isEmpty()) {
            precise.setTaskId(UUID.randomUUID().toString());
        }

        Integer crowNum = 0;
        // 如果是【千人邮件推送逻辑】，直接使用前面的传递的分组个数
        if (org.apache.commons.lang.StringUtils.equalsIgnoreCase(precise.getType(), "email")) {
            crowNum = precise.getCrowdNum();
        } else if (!StringUtils.isEmpty(precise.getGroupId())) {
            List<String> personList = customerService.listCustomerByGroupId(precise.getGroupId());
            if (null != personList) {
                crowNum = personList.size();
            }
        }
        precise.setCrowdNum(crowNum);
        int i = preciseDao.addPrecise(precise);

        if (i != 1) {
            throw new GlobalException(ResponseCode.FAIL);
        }
    }

    @Override
    public Boolean addWxPrecise(Map param) throws Exception {
        if (checkRenameTask(param.get("taskName").toString(), null, param.get("orgId").toString())) {
            throw GlobalException.build("任务名称[" + param.get("taskName").toString() + "]已存在,提交失败");
        }
        param.put("crowdNum", 0);
        if (!StringUtils.isEmpty(param.get("groupId"))) {
            List<String> personList = customerService.listCustomerByGroupId(param.get("groupId").toString());

            if (null != personList) {
                param.put("crowdNum", personList.size());
            }
        }
        if ((Integer) param.get("crowdNum") < 2) {
            throw GlobalException.build("所选人群中人数少于2人,提交失败");
        }
        return preciseDao.addWxPrecise(param);
    }

    @Override
    public Integer getTouchNum(String taskId) {
        try {
            Map<String, Object> precise = preciseDao.getPrecise(taskId);
            Map<String, Object> pushdata = new HashMap<>();
            if ("".equals(precise.get("msgId")) || (Integer) precise.get("touchNum") > 0) {
                return Integer.parseInt(precise.get("touchNum").toString());
            }
            pushdata.put("msgid", precise.get("msgId"));
            pushdata.put("token", newMallDao.getTokenByOrgId(precise.get("orgId")));
            Map<String, String> postParam = new HashMap<>();
            postParam.put("Content-Type", "application/json;charset=UTF-8");
            JSONObject jsonObject = (JSONObject) JSONArray.toJSON(pushdata);
            String postres = httpService.doPost(wxurl + "/index.php?s=/home/MassSend/get_masssend_result", jsonObject.toJSONString(), postParam);
            List<Map> res = (List<Map>) JSON.parse(postres);
            if (null != res && null != res.get(0)) {
                Map<String, Object> param = new HashMap<>();
                param.put("taskId", taskId);
                param.put("touchNum", res.get(0).get("SentCount"));
                param.put("wxTouch", res.get(0).get("SentCount"));
                preciseDao.updateWxPush(param);
            }
            return Integer.parseInt(res.get(0).get("SentCount").toString());
        } catch (Exception e) {
            LOGGER.error("获取群发结果失败：", e);
            throw GlobalException.build("获取群发结果失败");
        }
    }

    @Override
    public Boolean updateWxPush(Map param) {
        if (checkRenameTask(param.get("taskName").toString(), null, param.get("taskId").toString())) {
            throw GlobalException.build("任务名称[" + param.get("taskName").toString() + "]已存在,提交失败");
        }
        if (!StringUtils.isEmpty(param.get("groupId"))) {
            List<String> personList = customerService.listCustomerByGroupId(param.get("groupId").toString());

//            List<HashMap<String, Object>> personList = selfDao.getNeedPushUserListByGroupId(param.get("groupId").toString());
            if (null == personList) {
                param.put("crowdNum", 0);
            } else {
                param.put("crowdNum", personList.size());
            }
            if ((Integer) param.get("crowdNum") < 2) {
                throw GlobalException.build("所选人群中人数少于2人,提交失败");
            }
        }
        param.put("taskIdNew", UUID.randomUUID().toString());
        return preciseDao.updateWxPush(param);
    }

    @Override
    public Map<String, Object> getInfo(String taskId) {
        return preciseDao.getInfo(taskId);
    }

    @Override
    public void updatePrecise(Precise precise) throws Exception {
        if (StringUtils.isEmpty(precise.getTaskId())) {
            throw new GlobalException(new ResponseException(400, "计划ID不能为空"));
        }
        Integer crowNum = 0;
        if (!StringUtils.isEmpty(precise.getGroupId())) {
            List<String> personList = customerService.listCustomerByGroupId(precise.getGroupId());

//            List<HashMap<String, Object>> personList = selfDao.getNeedPushUserListByGroupId(precise.getGroupId());
            if (null != personList) {
                crowNum = personList.size();
            }
        }
        precise.setCrowdNum(crowNum);
        int i = preciseDao.updateByPrimaryKeySelective(precise);
        if (i != 1) {
            throw new GlobalException(ResponseCode.FAIL);
        }
    }

    @Override
    public Boolean delPrecise(String taskId) throws Exception {
        if (StringUtils.isEmpty(taskId)) {
            throw new GlobalException(new ResponseException(400, "计划ID不能为空"));
        }

        int delCount = preciseDao.deleteByPrimaryKey(taskId);
        if (delCount > 0) {
            return true;
        }
        throw new GlobalException(new ResponseException(400, "删除计划失败"));
    }

    @Override
    public Map<String, Object> getPrecise(String taskId) {
        if (StringUtils.isEmpty(taskId)) {
            throw new GlobalException(new ResponseException(400, "计划ID不能为空"));
        }

        Map<String, Object> precise = preciseDao.getPrecise(taskId);
        Object content = precise.get("content");
        Object parse = JSON.parse((String) content);
        precise.put("content", parse);
        List<Map<String, Object>> groupList = preciseDao.getGroupListByIds(precise.get("groupId").toString());
        precise.put("groupList", groupList);
        return precise;
    }

    private Boolean checkRenameTask(String taskName, String taskId, String orgId) {
        Integer taskCountByName = preciseDao.getTaskCountByName(taskName, taskId, orgId);
        return taskCountByName > 0;
    }

    @Override
    public Map<String, Object> getSendReport(String taskId) {
        Map<String, Object> sendReport = preciseDao.getSendReport(taskId);
        sendReport = (null == sendReport) ? new HashMap<>() : sendReport;
        sendReport.put("groupNum", 0);
        if (!StringUtils.isEmpty(sendReport.get("groupId"))) {
            String groupId = sendReport.get("groupId").toString();
            List<String> result = Arrays.asList(groupId.split(","));
            sendReport.put("groupNum", result.size());
        }
        sendReport.remove("groupId");


        /*============ 【千人演示邮件 数据统计】 todo 写新的接口===============*/


        //根据任务分组id查出当前分组下人邮件任务列表
        List<Map<String, Object>> demoListByTaskId = preciseDao.getDemoSendListByTaskID(taskId);

        if (!CollectionUtils.sizeIsEmpty(demoListByTaskId)) {
            sendReport.put("allSendCount", demoListByTaskId.size());
            // 分组数
            sendReport.put("groupNum", 1);

            //总人数
            sendReport.put("crowdNum", demoListByTaskId.size());

            // 过滤数据库发送成功数量
            int successCount = (int) demoListByTaskId.stream().filter(i -> ("1").equals(i.get("read_status").toString())).count();
            sendReport.put("successCount", successCount);

            //过滤出关注的人数
            int wxBindCount = (int) demoListByTaskId.stream().filter(i -> ("1").equals(i.get("wecome_status").toString())).count();
            sendReport.put("wxBindCount", wxBindCount);


            // 分组人数(触达人数)
            sendReport.put("touchNum", successCount);

            //推送报告 (新加字段 返回日志类型 1:邮箱阅读时间 2：微信关注时间)
            List<Map<String, Object>> pushReport = preciseDao.getPushReport(taskId);
            sendReport.put("readListByTask", pushReport);

            //阅读趋势
            List<Map<String, Object>> readTrend = preciseDao.getReadTrendReport(taskId);
            sendReport.put("readTrend", readTrend);

        }

        return sendReport;
    }

    /**
     * 【千人计划】创建分组
     * 【authSearcherWrapper】 人员筛选条件
     * email 邮件
     * domain 标签
     * city 地区
     * name 名字
     */
    @Override
    public void createGroup(PersonGroupDTO groupDTO) {

        //生成分组id
        groupDTO.setId(UUIDUtils.getUUID());

        //根据分组条件组合找到人员ids
        List<String> personList = groupDTO.getPersonList();
        if (CollectionUtils.isEmpty(personList)) {

            //对地区数据进行改造
            if (groupDTO.getAuthSearcherWrapper().containsKey("city")) {
                //改变地区格式 (浙江省,杭州市 => 浙江-杭州)
                Map<String, Object> authSearcherWrapper = groupDTO.getAuthSearcherWrapper();
                String city = CityFormatReplaceUtils.replaceChange(authSearcherWrapper.get("city").toString());
                authSearcherWrapper.put("city", city);
                groupDTO.setAuthSearcherWrapper(authSearcherWrapper);
            }

            List<Map<String, Object>> authList = this.getAuthList(groupDTO.getAuthSearcherWrapper());

            personList = authList.stream().map(i -> i.get("author_id").toString()).collect(Collectors.toList());
        }
        groupDTO.setGroupNum(personList.size());

        // 一个分组绑定多个用户
        List<Map<String, Object>> bindList = new ArrayList<>();
        for (String authId : personList) {
            Map<String, Object> authGroupBindMap = new HashMap<>();
            authGroupBindMap.put("groupId", groupDTO.getId());
            authGroupBindMap.put("authorId", authId);
            bindList.add(authGroupBindMap);
        }
        //创建分组
        preciseDao.createGroup(groupDTO);

        //添加绑定信息
        this.addPersonGroupBind(bindList);

    }

    /**
     * 【千人计划】获取分组列表
     */
    @Override
    public List<Map<String, Object>> getGroupList() {
        return preciseDao.getGroupList();
    }

    /**
     * 【千人计划】获取authList
     */
    @Override
    public List<Map<String, Object>> getAuthList(Map<String, Object> params) {
        params = MapUtils.isNotEmpty(params) ? params : new HashMap<>();
        return preciseDao.getAuthList(params);
    }

    /**
     * 【千人计划】获取任务task列表
     */
    @Override
    public List<AuthorTask> getTaskList() {

        //获取任务与发送成功数量的关系map
        List<Map<String, Object>> maps = preciseDao.taskIdAndSuccessSendMap();
        Map<Object, Object> successMap = maps.stream().collect(Collectors.toMap(item -> item.get("taskId"), item -> item.get("num")));

        List<AuthorTask> taskList = preciseDao.getTaskList();
        //插入数据
        for (AuthorTask authorTask : taskList) {
            authorTask.setTouchNum(Integer.parseInt(successMap.get(authorTask.getTaskId()).toString()));
        }
        return preciseDao.getTaskList();
    }

    /**
     * 【千人计划】获取根据taskId获取数据统计
     */
    @Override
    public Map<String, Object> getPushResultByTaskId(String taskId) {

        //任务详情
        Map<String, Object> taskInfo = this.getTaskInfo(taskId);

        //根据taskId获取所有的邮件状态列表
        List<Map<String, Object>> demoListByTaskId = preciseDao.getDemoSendListByTaskID(taskId);

        // 阅读成功数量
        int successCount = (int) demoListByTaskId.stream().filter(i -> ("1").equals(i.get("read_status").toString())).count();

        // 发送成功数量
        int touchNum = (int) demoListByTaskId.stream().filter(i -> ("1").equals(i.get("send_status").toString())).count();

        //微信绑定的数
        int wxBindCount = (int) demoListByTaskId.stream().filter(i -> ("1").equals(i.get("wecome_status").toString())).count();

        //获取推送报告
        List<Map<String, Object>> pushReport = preciseDao.getPushReport(taskId);

        //获取阅读趋势（key:时间 value:数量）
        List<Map<String, Object>> readTrendReport = preciseDao.getReadTrendReport(taskId);


        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put(Constants.PushResult.COUNT_SEND_ALL, demoListByTaskId.size());
        resultMap.put(Constants.PushResult.COUNT_SEND_SUCCESS, successCount);
        resultMap.put(Constants.PushResult.COUNT_WX_BIND, wxBindCount);
        resultMap.put(Constants.PushResult.LIST_READ, pushReport);
        resultMap.put(Constants.PushResult.TREND_READ, readTrendReport);

        resultMap.put("taskName", taskInfo.get("task_name"));
        resultMap.put("crowdNum", taskInfo.get("crowd_num"));
        resultMap.put("sendTime", taskInfo.get("send_time"));
        resultMap.put("touchNum", touchNum);

        return resultMap;
    }


    /**
     * 【千人计划】查看任务详情
     */
    @Override
    public Map<String, Object> getTaskInfo(String taskId) {
        return preciseDao.getTaskInfo(taskId);
    }

    /**
     * 【千人计划】加入分组与用户关系
     */
    public void addPersonGroupBind(List<Map<String, Object>> list) {
        preciseDao.addPersonGroupBindBatch(list);
    }


    /**
     * 【千人计划】 添加到任务列表
     */
    @Override
    @Transactional
    public void addPreciseToDemoTask(AuthorTask authorTask, HttpServletRequest request) throws ExecutionException, InterruptedException {

        /**
         *  1.创建真实邮件任务-author_task_list
         *  2.进行邮件发送业务逻辑
         *  2.为了保障聚合的查询任务-t_crm_tbl_precise_list[真实的业务流程不走该逻辑]
         */
        //1.创建真实邮件任务-author_task_list
        String groupId = authorTask.getGroupId();
        if (StringUtils.isEmpty(groupId)) {
            throw new GlobalException(new ResponseException(400, "分组不能为空"));
        }

        //去重后的邮件list，任务中涉及到的分组(多个分组的话以逗号分隔)
        List<String> emails = this.getAuthorEmailsListByGroupId(groupId)
                .stream().distinct().collect(Collectors.toList());

        //当前登录人的机构id
        PcUserInfo pcUserInfo = this.userInfoUtil.getPcUserInfo(request);
        String orgId = pcUserInfo.getOrgId();
        // 判断当前机构是否在该平台进行过微信认证
        isOrgWxBindFlag(orgId);

        //生成taskId
        authorTask.setTaskId(UUIDUtils.getUUID());
        String content = authorTask.getContent();
        String taskName = authorTask.getTaskName();
        Integer crowdNum = org.apache.commons.lang.StringUtils.split(groupId, ",").length;
        authorTask.setCrowdNum(crowdNum);

        //发送邮件
        Map<String, Object> sendMap = new HashMap<>();
        sendMap.put("content", content);
        sendMap.put("contentTest", content);
        sendMap.put("taskName", taskName);
        sendMap.put("taskId", authorTask.getTaskId());
        sendMap.put("orgId", orgId);
        sendMap.put("status", "1");//直接显示已执行
        sendMap.put("groupId", groupId);
        sendMap.put("type", "email");//邮件发送类型
        sendMap.put("pushType", "2");//自定义发送类型
        sendMap.put("createUserId", pcUserInfo.getAdminId());
        sendMap.put("crowdNum", crowdNum);//人群数量(分组个数)
        //发送后加入到任务表中
        preciseDao.addPreciseDemoTask(authorTask);

        //2.进行邮件发送业务逻辑
        this.sendPreciseEmail(sendMap, emails);

        //3.为了保障聚合的查询任务-t_crm_tbl_precise_list[真实的业务流程不走该逻辑]
        this.savePreciseTsk(sendMap);
    }

    private void savePreciseTsk(Map<String, Object> sendMap) {

        Precise precise = new Precise();
        try {
            precise = BeanMapUtils.mapToBean(sendMap, Precise.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        precise.setContent(com.alibaba.fastjson.JSON.toJSONString(sendMap));
        Date database = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(CalendarUtils.FORMAT);
        String format = sdf.format(database.getTime());
        precise.setSendTime(format);
        this.addPrecise(precise);
    }

    /**
     * 【千人计划】 发送邮件
     */
    public void sendPreciseEmail(Map<String, Object> sendMap, List<String> emails) throws ExecutionException, InterruptedException {
        personnelService.sendEmailToPesonnal(sendMap, emails);
    }

    /**
     * 【千人计划】根据分组id 查询相关人员邮件列表
     */
    @Override
    public List<String> getAuthorEmailsListByGroupId(String groupId) {
        //多个分组
        if (groupId.contains(",")) {
            return preciseDao.getEmailListByGroupIds(groupId.split(","));
        }
        return preciseDao.getEmailListByGroupId(groupId);

    }

    /**
     * 【千人计划】根据分组id 查询相关人员ids
     */
    @Override
    public List<String> getIdsListByGroupIds(List<String> list) {
       return preciseDao.getIdsListByGroupIds(list)
               .stream().distinct().collect(Collectors.toList());
    }


    /**
     * 判断当前机构是否在该平台进行过微信认证
     */
    private boolean isOrgWxBindFlag(String orgId) {
        Integer wxCount = sysConfig.getWxCountByOrgId(orgId);
        if (wxCount < 1) {
            throw new GlobalException(new ResponseException(400, "请先绑定公众号"));
        }
        return true;
    }



}
